#include"cmdTask.h"
#include<stdio.h>
#include"dirStack.h"
#include"ThreadPool.h"
#include<errno.h>
task_t *_task_init()
{
	task_t *task = (task_t *)malloc(sizeof(task_t));
	bzero(task, sizeof(task_t));
	task->_cmdType = CMD_TYPE_INIT;
	return task;
}

void doTask(task_t *ptask, ThreadPool *threadpool)
{
	CmdType taskType = ptask->_cmdType;
	int netfd = ptask->_clientFd;
	switch (taskType) {
	case CMD_TYPE_CD:
		cmdCd(ptask, threadpool); // 传递 netfd 以便与客户端通信
		break;
	case CMD_TYPE_LS:
		cmdLs(ptask, threadpool);
		break;
	case CMD_TYPE_PWD:
		cmdPwd(ptask, threadpool);
		break;
	case CMD_TYPE_MKDIR:
		cmdMkdir(ptask, threadpool);
		break;
	case CMD_TYPE_RMDIR:
		cmdRmdir(ptask, threadpool);
		break;
	case CMD_TYPE_REMOVE:
		cmdRemove(ptask, threadpool);
		break;
	case CMD_TYPE_PUTS://如果是客户端发来上传请求，则服务器执行下载
		cmdGets(threadpool,ptask); //保存到服务器本地
		break;
	case CMD_TYPE_GETS: //如果是客户端发来下载请求，则服务器执行发送
		cmdPuts(threadpool, ptask); //发送给客户端
		break;
	default:
		printf("Invalid Cmd\n"); // 修正拼写错误
		send(netfd, "ERROR: Invalid Command", 21, 0); // 通知客户端
		break;
	}
}


/*
 * 建立目录栈
 * 返回值为真：路径正确；假，路径错误
 * 用于获得当前的虚假工作路径、绝对工作路径
 *
 */

bool _get_dirStack(task_t *ptask, // 任务结构体
		   _dirStack_t *dirstack, // 目录栈地址
		   char *absDir[], // 绝对目录地址
		   char *fakeDir[] // 相对目录地址
)
{
	const char root[] =
		"/home/lunisolar/cpp/project/server/serverFrame/src/netdisk/"; //TODO 修改ming为用户名
	/* printf("curstack = %s\n", _dirStack_getDir(dirstack)); */
	char *cmdPath = strdup(ptask->_data);
	if (cmdPath == NULL) {
		fprintf(stderr, "empty path.\n");
		return false;
	}
	/* printf("cmdPath = %s\n", cmdPath); */
	char curpath[4096] = { 0 };
	char *token = strtok(cmdPath, "/");

	while (token) {
		/* printf("token = %s\n", token);// test */
		if (strcmp(token, ".") == 0) {
			token = strtok(NULL, "/");
			/* printf("curstack = %s\n", _dirStack_getDir(dirstack)); */
			continue;
		} else if (strcmp(token, "..") == 0) {
			if (_dirStack_pop(dirstack) == 1) {
				/* popFlag = true; */
				return false;
			}
		} else if (token) {
			_dirStack_push(dirstack, token);
		} else {
			break;
		}

		/* printf("curstack = %s\n", _dirStack_getDir(dirstack)); */
		token = strtok(NULL, "/");
	}

	strcpy(curpath, root);
	strcat(curpath, _dirStack_getDir(dirstack));
	curpath[strlen(curpath) - 1] = '\0';
	/* printf("curpath = %s\n", curpath); */

	char absstr[4096] = { 0 };
	strcat(absstr, root);
	strcat(absstr, curpath + strlen(root));
	/* printf("absolute path = %s\n", absstr); */
	/* printf("cd token = %s\n", token); */

	char fakerRoot[4096] = { 0 };
	strcat(fakerRoot, "~/netdisk/");
	strcat(fakerRoot, curpath + strlen(root));
	/* printf("fakeRoot = %s\n", fakerRoot); */

	//*absDir = (char*)calloc(strlen(absstr), sizeof(char));
	//*fakeDir = (char*)calloc(strlen(fakerRoot), sizeof(char));
	*absDir = strdup(absstr);
	*fakeDir = strdup(fakerRoot);

	/* printf("_get_dirStack end\n"); */

	return true;
}

void getUserDirStack(user_context **user,task_t *ptask, ThreadPool *threadpool)
{
	for (int i = 0; i < MAX_USER_NUM; i++) {
		if (threadpool->_user[i]._netfd == ptask->_clientFd) {
			*user = &threadpool->_user[i];
			break;
		}
	}
}

/* 命令cd */
void cmdCd(task_t *ptask, ThreadPool *threadpool)
{
	printf(">CD-------------------------------------------\n");
	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
    _dirStack_t *dirStack = user->dirStack;
	char curDir[4096] = { 0 };
	getcwd(curDir, sizeof(curDir));
	strcat(curDir, "/netdisk/");
	strcat(curDir, _dirStack_getDir(dirStack));
	//printf("curDir(before cd) = %s\n", curDir);
	strcat(curDir, ptask->_data);
	if (access(curDir, F_OK) != 0) {
		fprintf(stderr, "CD FAILED : directory.\n");
		//free(cmdPath);// TODO
		return;
	}

	char *absDir;
	char *fakeDir;

	// 临时目录栈 用于在pop错误时恢复原来的目录
	_dirStack_t tmpStack;
	_dirStack_initSlience(&tmpStack);
	_dirStack_copy(&tmpStack, dirStack);

	//printf("curstack = %s\n", _dirStack_getDir(dirStack));
	/* printf("tmpstack = %s\n", _dirStack_getDir(&tmpStack)); */

	if (_get_dirStack(ptask, dirStack, &absDir, &fakeDir) == false) {
		fprintf(stderr, "CD FAILED : no access right.\n");
		_dirStack_copy(dirStack, &tmpStack);
		printf("curstack = %s\n", _dirStack_getDir(dirStack));
		/* printf("tmpstack = %s\n", _dirStack_getDir(&tmpStack)); */
		return;
	}
	//printf("curFakeDir(after cd) = %s\n", fakeDir);
	//printf("curAbsDir(after cd) = %s\n", absDir);

	// 如果获取目录成功，则继续处理
	printf("CD SUCCESS!\n");
}

/* 命令ls */
void cmdLs(task_t *ptask, ThreadPool *threadpool)
{
	printf(">LS-------------------------------------------\n");
	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
	_dirStack_t *dirStack = user->dirStack;
	char *absDir;
	char *fakeDir;
	if (_get_dirStack(ptask, dirStack, &absDir, &fakeDir) == false) {
		fprintf(stderr, "LS FAILED: cant open dir.\n");
		return;
	}
	//printf("absDir = %s\n", absDir);
	//printf("fakeDir = %s\n", fakeDir);
	struct stat st;
	int ret = stat(absDir, &st);
	ERROR_CHECK(ret, -1, "lstat");
	if (!S_ISDIR(st.st_mode)) {
		fprintf(stderr, "LS FAIRED: not a directory.\n");
		return;
	}
	DIR *dir = opendir(absDir);
	ERROR_CHECK(dir, NULL, "open dir");

	struct dirent *entry;
	int rowLimit = 0;
	while ((entry = readdir(dir)) != NULL) {
		printf("%s ", entry->d_name);
        send(ptask->_clientFd, entry->d_name, strlen(entry->d_name), 0);
		++rowLimit;
		if (rowLimit >= 8) { // 一行限制8个
			rowLimit = 0;
			printf("\n");
		}
	}
	printf("\n");

	printf(" LS SUCCESS!\n");
}

/* 命令pwd */
void cmdPwd(task_t *ptask, ThreadPool *threadpool)
{
	printf(">PWD-------------------------------------------\n");
	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
	_dirStack_t *dirStack = user->dirStack;
	char *absDir;
	char *fakeDir;
	if (_get_dirStack(ptask, dirStack, &absDir, &fakeDir) == false) {
		printf("PWD FAILED!\n");
		return;
	}
	printf("pwd = %s\n", fakeDir);
	send(ptask->_clientFd, fakeDir, strlen(fakeDir), 0);
	printf("PWD SUCCESS!\n");
}
/* 命令mkdir */
void cmdMkdir(task_t *ptask, ThreadPool *threadpool)
{
	printf(">MKDIR-------------------------------------------\n");
	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
	_dirStack_t *dirStack = user->dirStack;
	char *absDir;
	char *fakeDir;
	if (_get_dirStack(ptask, dirStack, &absDir, &fakeDir) == false) {
		printf("PWD FAILED!\n");
		return;
	}
    int mkdir_res = makeDir(absDir);
    ERROR_CHECK(mkdir_res, -1, "MakeDir error");
}

/* 命令rmdir */
void cmdRmdir(task_t *ptask, ThreadPool *threadpool)
{
	printf(">RMDIR-------------------------------------------\n");
	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
	_dirStack_t *dirStack = user->dirStack;
	char *absDir;
	char *fakeDir;
	if (_get_dirStack(ptask, dirStack, &absDir, &fakeDir) == false) {
		printf("PWD FAILED!\n");
		return;
	}
    int rmdir_res = removeDir(absDir);
    ERROR_CHECK(rmdir_res, -1, "RemoveDir error");
}

char *concatRootAndPath(_dirStack_t *dirStack, const char *root)
{
	char *relPath = _dirStack_traverseToString(dirStack);
	size_t rootLen = strlen(root);
	size_t relLen = strlen(relPath);

	char *fullPath = NULL;

	if (relLen == 0) {
		// 如果 relPath 为空，直接返回 root
		fullPath = strdup(root);
	} else {
		// 否则拼接 root 和 relPath
		fullPath = malloc(rootLen + relLen + 2); // +2 为 '/' 和 '\0'
		if (fullPath == NULL) {
			perror("malloc failed");
			free(relPath);
			return NULL;
		}
		strcpy(fullPath, root);
		strcat(fullPath, relPath);
        strcat(fullPath, "/");
	}

	free(relPath);
	return fullPath;
}

// 服务器处理客户端上传文件（接收文件）
void cmdGets(ThreadPool *threadpool, task_t *ptask) {
    printf("> DOWNLOAD-------------------------------------------\n");

    user_context *user = NULL;
    getUserDirStack(&user, ptask, threadpool);
    void *dirStack = user->dirStack;

    const char root[] = "/home/lunisolar/cpp/project/server/serverFrame/src/netdisk/";
    char *fullpath = concatRootAndPath(dirStack, root);

    // 防止路径穿越
    if (strstr(ptask->_data, "..")) {
        printf("Invalid file path: %s\n", ptask->_data);
        return;
    }

    char target_path[256];
    snprintf(target_path, sizeof(target_path), "%s%s", fullpath, ptask->_data);
    printf("Target Path: %s\n", target_path);

    // 从 epoll 中移除客户端文件描述符
    epollDel(threadpool->epfd, ptask->_clientFd);

    

    // 重新将客户端文件描述符加入 epoll
    epollAdd(threadpool->epfd, ptask->_clientFd);
    
}

// 服务器处理客户端下载请求（发送文件）
void cmdPuts(ThreadPool *threadpool, task_t *ptask)
{
	printf("> UPLOAD-------------------------------------------\n");

	user_context *user = NULL;
	getUserDirStack(&user, ptask, threadpool);
	_dirStack_t *dirStack = user->dirStack;

	const char root[] =
		"/home/lunisolar/cpp/project/server/serverFrame/src/netdisk/";
	char *fullpath = concatRootAndPath(dirStack, root);
	char target_path[256];
	snprintf(target_path, sizeof(target_path), "%s%s", fullpath,
		 ptask->_data);
	printf("Target Path: %s\n", target_path);

	// 从 epoll 中移除客户端文件描述符
	epollDel(threadpool->epfd, ptask->_clientFd);

	// 重新将客户端文件描述符加入 epoll
	epollAdd(threadpool->epfd, ptask->_clientFd);
}

/* 命令remove,删除文件 */
void cmdRemove(task_t *ptask, ThreadPool *threadpool)
{
	
}
